#include "scan_pro.h"
namespace hs{

// 初始化函数
char* initInput(char* inputFN){ 
    if (inputFN == nullptr) {
        inputFN = "/home/wang/scanpro/scan_hs/src/tel_utf8.txt";
    }
    return inputFN;
}

// 模式编译
bool patternsCompile(hs_database_t** database, const char* patterns[], unsigned int elementCount){
    // 对应模式ID
    const unsigned int ids[] = {ID_PHONE, ID_EMAIL};
    
    // 对应标志
    const unsigned int flags[] = {        
        HS_FLAG_SOM_LEFTMOST,             
        HS_FLAG_SOM_LEFTMOST            
    };
    hs_compile_error_t* compile_err;
    
    // 编译多模式
    if (hs_compile_multi(patterns, flags, ids, elementCount, 
                        HS_MODE_BLOCK, NULL, database, &compile_err) != HS_SUCCESS) {
        fprintf(stderr, "编译失败 %s\n", compile_err->message);
        hs_free_compile_error(compile_err);                  
        return false;
    }
    
    return true;
}

// 读文件
bool readInputData(char** inputData, const char* inputFN, unsigned int* length) {
    FILE *f = fopen(inputFN, "rb");
    if (!f) {
        fprintf(stderr, "打开文件失败\"%s\": %s\n", inputFN,
                strerror(errno));
        return false;  // 返回bool类型
    }
    
    // 将文件指针移动到末尾
    if (fseek(f, 0, SEEK_END) != 0) {
        fprintf(stderr, "ERROR\"%s\": %s\n", inputFN,
                strerror(errno));
        fclose(f);
        return false;
    }
    
    // 获取文件长度
    long dataLen = ftell(f);
    
    // 处理文件长度异常
    if (dataLen < 0) {
        fprintf(stderr, "ERROR%s\n", strerror(errno));
        fclose(f);
        return false;
    }
    
    // 将文件指针重新移动到文件开始
    if (fseek(f, 0, SEEK_SET) != 0) {
        fprintf(stderr, "文件指针操作失败\"%s\": %s\n", inputFN,
                strerror(errno));
        fclose(f);
        return false;
    }

    /* 适当地限制缓冲区的大小。 */
    if ((unsigned long)dataLen > UINT_MAX) {
        dataLen = UINT_MAX;
        printf("文件%ld字节超出UINT_MAX\n", dataLen);
    } else if (dataLen == 0) {
        fprintf(stderr, "文件\"%s\"为空\n", inputFN);
        fclose(f);
        return false;
    }
    
    /* 分配内存块存储数据 */
    *inputData = (char *)malloc(dataLen);
    if (!*inputData) {  // 检查指针是否分配成功
        fprintf(stderr, "内存块分配%ld字节失败\n", dataLen);
        fclose(f);
        return false;
    }

    char *p = *inputData;
    size_t bytesLeft = dataLen;
    
    /* 使用循环和 fread 函数分块读取文件内容到内存中 */
    while (bytesLeft) {
        size_t bytesRead = fread(p, 1, bytesLeft, f);
        bytesLeft -= bytesRead;
        p += bytesRead;
        if (ferror(f) != 0) {
            fprintf(stderr, "读文件到内存块失败\n");
            free(*inputData);
            fclose(f);
            return false;
        }
    }

    fclose(f);
    *length = (unsigned int)dataLen;
    return true;
}

// 临时空间创建
bool scratchCreat(hs_database_t* database, hs_scratch_t** scratch){
    if (hs_alloc_scratch(database, scratch) != HS_SUCCESS) {
        fprintf(stderr, "临时空间创建失败\n");
        return false;
    }
    return true;
}

// 执行扫描
bool scanData(hs_database_t* database, char* inputData, unsigned int length, hs_scratch_t* scratch){
    // 执行扫描
    if (hs_scan(database, inputData, length, 0, scratch, eventHandler, inputData) != HS_SUCCESS) {
        fprintf(stderr, "扫描错误\n");
        return false;
    }   
    return true;
}

// 事件处理函数
int eventHandler(unsigned int id, unsigned long long from,
                        unsigned long long to, unsigned int flags, void *context) {
    char *inputData = (char *)context;
    
    const char* type = (id == ID_PHONE) ? "手机号" : "邮箱";
    size_t len = to - from;
    
    printf("识别到 %s: %.*s (位置: %llu-%llu)\n", 
           type, (int)len, inputData + from, 
           from, to);
    return 0;
}

// 主扫描函数
bool scanHs(const char* patterns[], const unsigned int elementCount, char* inputFN)
{
    inputFN = initInput(inputFN);
    hs_database_t* database = nullptr;

    // 编译模式
    if (!patternsCompile(&database, patterns, elementCount)) {
        return false;
    }
    
    // 读取文件
    char *inputData = nullptr;
    // 获取文件长度
    unsigned int length = 0;

    if (!readInputData(&inputData, inputFN, &length)) {
        hs_free_database(database);
        return false;
    }
    //创建临时空间
    hs_scratch_t* scratch = nullptr;
    if (!scratchCreat(database, &scratch)) {
        free(inputData);
        hs_free_database(database); 
        return false;
    }

    //执行扫描
    bool scanSuccess = scanData(database, inputData, length, scratch);
    if (scanSuccess) {
        printf("扫描完成\n");
    } else {
        printf("扫描失败\n");
    }
    // 释放资源
    hs_free_scratch(scratch);
    free(inputData);
    hs_free_database(database);

    return scanSuccess;
}

} // namespace hs
